#include "client.h"
#include <string_view>
#include <iostream>
#include <ctime>
#include <fstream>

#include <cppbase/cstring.h>
#include "config.h"
namespace Http
{

	int Request::parse_request(char *beg, int size)
	{
		CString cs(beg, beg + size);
		auto pos = cs.find(std::string("\r\n"), 0, MAX_URL_LEN);
		CString firstline(beg, beg + pos);
		auto cmd = firstline.split(" ");
		if (cmd.size() != 3)
		{
			status = Status::BadRequest;
			return 1;
		}
		if (cmd.front() == "GET")
		{
			method = Method::Get;
		}
		else if (cmd.front() == "GET")
			method = Method::Post;
		else
		{
			status = Status::BadRequest;
			return 1;
		}

		cmd.pop_front();
		std::swap(url, cmd.front());
		CString urlcstring(url.data(), url.size());
		auto dump = urlcstring.find("?");
		if (dump >= 0)
		{
			urlcstring.seekg(dump + 1);
			query = urlcstring.parse_kv("=", "&");
		}

		std::swap(protocol, cmd.back());
		cs.seekg(pos + 2); //next line
		int lasthead_pos = cs.find(std::string("\r\n\r\n"));
		if (lasthead_pos < 0)
		{
			status = Status::BadRequest;
			return 1;
		}
		lasthead_pos += 2; //now point to first char of content
		head = cs.parse_kv(": ", "\r\n", lasthead_pos);

		if (size > lasthead_pos)
		{
			content.resize(size - lasthead_pos);
			memcpy(content.data(), beg + lasthead_pos, content.size());
		}

		status = Status::OK;
		return 1;
	}
	/**
	 * Warning: You MUS free the momery after usage.
	 * 
	*/
	struct iovec Request::make_reply_line()
	{

		auto code = std::to_string(int(status));
		struct iovec v;
		v.iov_len = protocol.size() + 1 + code.size() + 1 + 4;
		v.iov_base = malloc(v.iov_len);

		memcpy(v.iov_base, protocol.data(), protocol.size());
		int pos = protocol.size();
		((char *)v.iov_base)[pos] = ' ';
		pos += 1;
		memcpy((char *)v.iov_base + pos, code.data(), code.size());
		pos += code.size();
		((char *)v.iov_base)[pos] = ' ';
		pos += 1;
		memcpy((char *)v.iov_base + pos, "OK\r\n", 4);
		return v;
	}
	void Reply::set_head(std::string k, std::string v)
	{
		head[std::move(k)] = std::move(v);
	}
	void Reply::make_default_head()
	{
		//	head["Connection"] = "close";
		auto f = head.find("Content-Type");
		if (f == head.end())
			head["Content-Type"] = "text/html; charset=UTF-8";

		head["Content-Length"] = std::to_string(content_length());

		time_t now = std::time(0); //seconds passed since 1970
		tm *ltm = std::gmtime(&now);
		std::string date;
		date.resize(30);
		std::strftime(&date[0], date.size(), "%a, %d %b %Y %H:%M:%S GMT", ltm);
		while (date.back() == '\0')
			date.resize(date.size() - 1);
		head["Date"] = date;
		head["Expires"] = std::move(date);
	}
	/**
 * Warning: You MUST free returned memory after usage.
 * 
*/
	struct iovec Reply::make_head_buf()
	{

		struct iovec v;
		if (head.size() == 0)
			make_default_head();
		v.iov_len = 0;
		for (auto &i : head)
		{
			v.iov_len += i.first.size() + i.second.size() + 4;
		}
		v.iov_len += 2;
		v.iov_base = (char *)malloc(v.iov_len);
		int pos = 0;
		for (auto &i : head)
		{
			memcpy((char *)v.iov_base + pos, i.first.data(), i.first.size());
			pos += i.first.size();
			((char *)v.iov_base)[pos] = ':';
			((char *)v.iov_base)[pos + 1] = ' ';
			pos += 2;
			memcpy((char *)v.iov_base + pos, i.second.data(), i.second.size());
			pos += i.second.size();
			((char *)v.iov_base)[pos] = '\r';
			((char *)v.iov_base)[pos + 1] = '\n';
			pos += 2;
		}
		((char *)v.iov_base)[pos] = '\r';
		((char *)v.iov_base)[pos + 1] = '\n';

		return v;
	}

}